/**
 * Created : Apr 10, 2012
 *
 * @author pquiring
 */

import java.awt.*;
import java.awt.event.*;

import javaforce.*;
import javaforce.linux.*;

public class SoundWindow extends javax.swing.JWindow {

  public static int volume = 50;
  public static boolean muted = false;
  public static int sinkIdx = -1;

  /**
   * Creates new form CalendarWindow
   */
  public SoundWindow(Point pos, int width) {
    super();
    initComponents();
    JFLog.log("soundWindow:pos=" + pos.x + "," + pos.y);
    Dimension d = getPreferredSize();
    setLocation(pos.x - (d.width - width)/2, pos.y - d.height - 5);
    setAlwaysOnTop(true);
    toFront();
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        slider = new javax.swing.JSlider();
        mute = new javax.swing.JToggleButton();

        slider.setOrientation(javax.swing.JSlider.VERTICAL);
        slider.setValue(volume);
        slider.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderStateChanged(evt);
            }
        });

        mute.setSelected(muted);
        mute.setText("X");
        mute.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                muteStateChanged(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(mute))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(25, 25, 25)
                        .addComponent(slider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(slider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(mute)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

  private void sliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderStateChanged
    if (sinkIdx == -1) return;
    volume = slider.getValue();
    try {
      Runtime.getRuntime().exec(new String[] {"pactl","set-sink-volume","" + sinkIdx,"" + volume + "%"});
    } catch (Exception e) {
      JFLog.log(e);
    }
  }//GEN-LAST:event_sliderStateChanged

  private void muteStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_muteStateChanged
    if (sinkIdx == -1) return;
    muted = mute.isSelected();
    try {
      Runtime.getRuntime().exec(new String[] {"pactl","set-sink-mute","" + sinkIdx,muted ? "1" : "0"});
    } catch (Exception e) {
      JFLog.log(e);
    }
  }//GEN-LAST:event_muteStateChanged

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JToggleButton mute;
    private javax.swing.JSlider slider;
    // End of variables declaration//GEN-END:variables

  public void addMouseListener(MouseListener ml) {
    super.addMouseListener(ml);
    slider.addMouseListener(ml);
    mute.addMouseListener(ml);
  }

  public void mute() {
    mute.setSelected(!mute.isSelected());
  }

  public void adjustVolume(int delta) {
    int newLevel = slider.getValue() + delta;
    if (newLevel < 0) newLevel = 0;
    if (newLevel > 100) newLevel = 100;
    slider.setValue(newLevel);
  }

  public static void reload(Dock.Config config) {
    PulseAudio.list();
    if (PulseAudio.sinks.size() > 0) {
      PulseAudio.Sink sink = PulseAudio.sinks.get(0);
      volume = sink.volume;
      muted = sink.muted;
      sinkIdx = sink.idx;
      JFLog.log("Sound:Sink idx=" + sinkIdx);
    }
    config.card = new Dock.Card[PulseAudio.cards.size()];
    for(int a=0;a<PulseAudio.cards.size();a++) {
      config.card[a] = new Dock.Card();
      config.card[a].idx = PulseAudio.cards.get(a).idx;
      config.card[a].activeProfile = PulseAudio.cards.get(a).activeProfile;
    }
    config.sink = new Dock.Sink[PulseAudio.sinks.size()];
    for(int a=0;a<PulseAudio.sinks.size();a++) {
      config.sink[a] = new Dock.Sink();
      config.sink[a].idx = PulseAudio.sinks.get(a).idx;
      config.sink[a].activePort = PulseAudio.sinks.get(a).activePort;
      config.sink[a].volume = PulseAudio.sinks.get(a).volume;
    }
    config.source = new Dock.Source[PulseAudio.sources.size()];
    for(int a=0;a<PulseAudio.sources.size();a++) {
      config.source[a] = new Dock.Source();
      config.source[a].idx = PulseAudio.sources.get(a).idx;
      config.source[a].activePort = PulseAudio.sources.get(a).activePort;
      config.source[a].volume = PulseAudio.sources.get(a).volume;
    }
  }

  public static void init(Dock.Config config) {
    if (config == null) return;
    if (config.card != null) {
      for(int a=0;a<config.card.length;a++) {
        try {
          ShellProcess sp = new ShellProcess();
          sp.run(new String[] {"pactl","set-card-profile","" + config.card[a].idx, config.card[a].activeProfile}, true);
          if (sp.getErrorLevel() != 0) {
            JFLog.log("Failed to set card profile");
          }
        } catch (Exception e) {
          JFLog.log(e);
        }
      }
    }
    if (config.sink != null) {
      for(int a=0;a<config.sink.length;a++) {
        try {
          ShellProcess sp = new ShellProcess();
          sp.run(new String[] {"pactl","set-sink-port","" + config.sink[a].idx, config.sink[a].activePort}, true);
          if (sp.getErrorLevel() != 0) {
            JFLog.log("Failed to set sink port");
          }
          sp.run(new String[] {"pactl","set-sink-volume","" + config.sink[a].idx, config.sink[a].volume + "%"}, true);
          if (sp.getErrorLevel() != 0) {
            JFLog.log("Failed to set sink port");
          }
        } catch (Exception e) {
          JFLog.log(e);
        }
      }
    }
    if (config.source != null) {
      for(int a=0;a<config.source.length;a++) {
        try {
          ShellProcess sp = new ShellProcess();
          sp.run(new String[] {"pactl","set-source-port","" + config.source[a].idx, config.source[a].activePort}, true);
          if (sp.getErrorLevel() != 0) {
            JFLog.log("Failed to set source port");
          }
          sp.run(new String[] {"pactl","set-source-volume","" + config.source[a].idx, config.source[a].volume + "%"}, true);
          if (sp.getErrorLevel() != 0) {
            JFLog.log("Failed to set source port");
          }
        } catch (Exception e) {
          JFLog.log(e);
        }
      }
    }
    reload(config);
  }

  public static void setVolume(int v) {
    volume = v;
  }
}
